home *** CD-ROM | disk | FTP | other *** search
-
- /* Generated by Interface Builder */
-
- // Handles moving and rendering the Pac, whether under player or demo control.
-
- #import <libc.h>
- #import "Player.h"
- #import "Monster.h"
- #import "Maze.h"
- #import "PacManView.h"
- #import "PlayerUpView.h"
- #import <appkit/NXImage.h>
- #import <appkit/Application.h>
- #import <appkit/graphics.h>
- #import "PacMovement.h"
-
- // used to translate PAC_<direction> to px, py velocities
- static int pacxvec[9] = { 0, 2, -2, 0, 0, 0, 0, 0, 0 };
- static int pacyvec[9] = { 0, 0, 0, 0, -2, 0, 0, 0, 2 };
- //static int opdir[9] = { 0, 2, 1, 0, 8, 0, 0, 0, 4 };
- static int bothdir[9] = { 0, 3, 3, 0, 12, 0, 0, 0, 12 };
-
- // the y-coord in the Pacs.tiff image indexed by direction
- static int pacypic[9] = { 0, 5 * PAC_WIDTH, 4 * PAC_WIDTH, 0,
- 6 * PAC_WIDTH, 0, 0, 0, 7 * PAC_WIDTH };
- static int pacydie[9] = { 0, 1 * PAC_WIDTH, 0, 0,
- 2 * PAC_WIDTH, 0, 0, 0, 3 * PAC_WIDTH };
-
-
- @implementation Player
-
- - init // initialize the player
- {
- [super init];
- pacs = [NXImage findImageNamed:"Pacs.tiff"];
- nextDir = PAC_STOP;
- curDir = PAC_STOP;
- return self;
- }
-
- - (BOOL)newPlayer // get and set up a new Pac. Returns NO if can't
- {
- if (![pacsLeft nextPac]) return NO; // no pacs left
- [self resetPlayer];
- return YES;
- }
-
- - resetPlayer // reset all player info
- {
- curDir = PAC_RIGHT;
- nextDir = PAC_RIGHT;
- px = 0; py = 0;
- state = PAC_ALIVE;
- cycle = 0;
- lastx = - 4 * GHOST_SIZE;
- lasty = - 4 * GHOST_SIZE;
- [maze playerPosition:&myX :&myY];
- return self;
- }
-
- - (BOOL)pacAlive // returns YES if Pac is alive
- {
- if (state < PAC_ALIVE) return NO;
- return YES;
- }
-
- - demoMove:sender // handles Pac movement during the demo sequence
- {
- int i, zz; float xx, yy; int zi = 1;
- int ghost_x = 0;
- int ghost_y = 0;
- int closest = (BLOCK_WIDTH + BLOCK_HEIGHT) * GHOST_SIZE;
- register int tdir = 0x0f;
- register int sense = 0;
- int dx = myX % GHOST_SIZE; int dy = myY % GHOST_SIZE;
-
- // keep us in the track between maze walls
- if (dx) tdir &= 0x03;
- if (dy) tdir &= 0x0c;
-
- for (i=0; i<4; i++) { // find closest ghost; run away from it.
- [[sender ghost:i] at:&xx :&yy];
- zz = abs(xx - myX) + abs(yy - myY);
- if (zz < closest) {
- zi = i;
- closest = zz;
- ghost_x = xx;
- ghost_y = yy;
- } }
-
- // first, find the directions in which pac can go
- if ((abs(ghost_x - myX) >= GHOST_SIZE * 2 - 2) ||
- (abs(ghost_y - myY) >= GHOST_SIZE * 2 - 2)) {
- if ([maze playerWall:(myX+GHOST_SIZE) :myY] || (px < 0))
- tdir &= ~0x01;
- if ([maze playerWall:(myX-1) :myY] || (px > 0)) tdir &= ~0x02;
- if ([maze playerWall:myX :(myY-1)] || (py > 0)) tdir &= ~0x04;
- if ([maze playerWall:myX :(myY+GHOST_SIZE)] || (py < 0))
- tdir &= ~0x08;
- if ((random() & 0x0f) > 10) {
- // worry about shorter distance first.
- if (abs(ghost_x - myX) < abs(ghost_y - myY)) {
- if (tdir & 0x03) tdir &= 0x03;
- } else {
- if (tdir & 0x0c) tdir &= 0x0c;
- } }
- } else { // if a ghost is close by, we can reverse direction.
- if ([maze playerWall:myX :(myY-1)]) tdir &= ~0x04;
- if ([maze playerWall:myX :(myY+GHOST_SIZE)]) tdir &= ~0x08;
- if ([maze playerWall:(myX+GHOST_SIZE) :myY]) tdir &= ~0x01;
- if ([maze playerWall:(myX-1) :myY]) tdir &= ~0x02;
- }
-
- // now choose the new direction for the pac
- if ([[sender ghost:zi] canBeEaten]) {
- // chase an eatable ghost
- sense = demofind[sgn(ghost_y - myY) + 1][sgn(ghost_x - myX) + 1];
- px = chasexvec[tdir][sense];
- py = chaseyvec[tdir][sense];
- } else {
- if (((abs(ghost_x - myX) <= GHOST_SIZE * 2 - 2) &&
- (abs(ghost_y - myY) <= GHOST_SIZE * 2 - 2)) ||
- ((random() & 0x0f) > 2)) { // if close or random allows, go
- // according to program
- sense = demofind[sgn(ghost_y - myY) + 1][sgn(ghost_x - myX) + 1];
- } else { // random direction occasionally
- sense = random() & 0x07;
- }
- px = demoxvec[tdir][sense];
- py = demoyvec[tdir][sense];
- } // set up the direction:
- curDir = demoDir[sgn(py) + 1][sgn(px) + 1];
- return self;
- }
-
- - move:sender // Move the PacMan one animation frame
- {
- int dx = myX % PAC_WIDTH; int dy = myY % PAC_WIDTH;
- register int tdir = 0x0f;
-
- if (state < PAC_DEAD) { // Pac is dying
- state++;
- } else if (state >= PAC_ALIVE) { // Pac is alive, so move it
-
- if ([gameView demoMode]) {
- // if demo mode, we move the pac ourselves
- [self demoMove:sender];
- } else {
- // if not demo mode, we let the user decide how to move the pac.
- // first, find the directions in which the pac can go
- if (dx || dy) tdir = bothdir[curDir]; // curr. dir or opp.
- // direction are allowed; other dir. only at junctions.
- if ([maze playerWall:(myX+PAC_WIDTH) :myY]) tdir &= ~PAC_RIGHT;
- if ([maze playerWall:(myX-2) :myY]) tdir &= ~PAC_LEFT;
- if ([maze playerWall:myX :(myY-2)]) tdir &= ~PAC_DOWN;
- if ([maze playerWall:myX :(myY+PAC_WIDTH)]) tdir &= ~PAC_UP;
-
- // see if we can go the "next" direction the player wants or not...
- if (nextDir & tdir) { // we can!
- curDir = nextDir;
- }
- // now choose the new direction for the pac
- // the "&" makes sure we stop if we can't go further in this dir.
- px = pacxvec[curDir & tdir];
- py = pacyvec[curDir & tdir];
- }
-
- } else { // Pac is dead so do nothing.
- px = 0; py = 0;
- }
- return self;
- }
-
- - newDirection:(int)newDir // send Pac in new direction.
- {
- nextDir = newDir;
- return self;
- }
-
- - pacDie { state = PAC_DYING; return self; } // the pac will melt
-
- - renderAt:(int)posx :(int)posy move:(BOOL)moveOk // draw pac
- // you should lock focus on view that gets the Pac first.
- {
- NXRect from;
- NXPoint pos;
-
- [super renderAt:posx :posy move:moveOk];
-
- pos.x = myX + posx; pos.y = myY + posy;
-
- if (state == PAC_ALIVE) { // draw living pac
- NXSetRect(&from, cycle * PAC_WIDTH, pacypic[curDir],
- PAC_WIDTH, PAC_WIDTH);
- } else if (state < PAC_DEAD) { // draw dying pac
- NXSetRect(&from, (state - PAC_DYING) * PAC_WIDTH, pacydie[curDir],
- PAC_WIDTH, PAC_WIDTH);
- if (!cycle) state++;
- if (cycle == 1) cycle = -1; // change period while we die
- } else { // if dead, draw no pac (upper rt. of image is blank)
- NXSetRect(&from, 10 * PAC_WIDTH, 7 * PAC_WIDTH,
- PAC_WIDTH, PAC_WIDTH);
- }
- [pacs composite:NX_SOVER fromRect:&from toPoint:&pos];
-
- cycle++; if (cycle > 5) cycle = 0; // cycle through six images.
- return self;
- }
-
-
- @end
-